﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Text;

public class ByteBuffer
{
    MemoryStream stream = null;
    BinaryWriter writer = null;
    BinaryReader reader = null;
    public ByteBuffer()
    {
        stream = new MemoryStream();
        writer = new BinaryWriter(stream);
    }

    public ByteBuffer(byte[] data)
    {
        if (data != null)
        {
            stream = new MemoryStream(data);
            reader = new BinaryReader(stream);
        }
        else
        {
            stream = new MemoryStream();
            writer = new BinaryWriter(stream);
        }
    }

    public void Close()
    {
        if (writer != null) writer.Close();
        if (reader != null) reader.Close();

        stream.Close();
        writer = null;
        reader = null;
        stream = null;
    }
    public void WriteBool(bool val)
    {
        writer.Write((bool)val);
    }

    public void WriteByte(int v)
    {
        writer.Write((byte)v);
    }
    public void WriteInt8(SByte val)
    {
        writer.Write((SByte)val);
    }

    public void WriteUInt8(Byte val)
    {
        WriteByte(val);
    }
    public void WriteShort(short v)
    {
        writer.Write((short)v);
    }
    public void WriteUInt16(ushort val)
    {
        writer.Write((ushort)val);
    }
    public void WriteInt16(Int16 val)
    {
        WriteShort(val);
    }

    public void WriteInt(int v)
    {
        writer.Write((int)v);
    }
    public void WriteInt32(int val)
    {
        WriteInt(val);
    }

    public void WriteUInt32(uint v)
    {
        writer.Write((uint)v);
    }

    public void WriteLong(long v)
    {
        writer.Write((long)v);
    }

    public void WriteUInt64(ulong v)
    {
        writer.Write((ulong)v);
    }
    public void WriteInt64(long v)
    {
        WriteLong(v);
    }

    public void WriteFloat(float v)
    {
        byte[] temp = BitConverter.GetBytes(v);
        ////Array.Reverse(temp);
        writer.Write(BitConverter.ToSingle(temp, 0));
    }

    public void WriteDouble(double v)
    {
        byte[] temp = BitConverter.GetBytes(v);
        //Array.Reverse(temp);
        writer.Write(BitConverter.ToDouble(temp, 0));
    }

    public void WriteString(string v)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(v);
        writer.Write((ushort)bytes.Length);
        writer.Write(bytes);
    }

    public void WriteBytes(byte[] v,bool writeLen = true)
    {
        if(writeLen)
            writer.Write((ushort)v.Length);
        writer.Write(v);
    }

    public void WriteVecUInt8(byte[] v)
    {
        writer.Write((ushort)v.Length);
        writer.Write(v);
    }

    public void WriteVecUInt8(List<Byte> vec)
    {
        WriteArrayLength((ushort)vec.Count);

        foreach (Byte v in vec)
            WriteUInt8(v);
    }
    public void WriteVecUInt32(List<UInt32> vec)
    {
        WriteArrayLength((UInt16)vec.Count);
        foreach (UInt32 v in vec)
            WriteUInt32(v);
    }

    public void WriteVecUInt64(List<UInt64> vec)
    {
        WriteArrayLength((UInt16)vec.Count);
        foreach (UInt64 v in vec)
            WriteUInt64(v);
    }
    public void WriteVecString(List<string> vec)
    {
        WriteArrayLength((UInt16)vec.Count);
        foreach (string v in vec)
            WriteString(v);
    }

    public void WriteArrayLength(ushort v)
    {
        WriteUInt16((ushort)v);
    }

    public byte ReadByte()
    {
        return reader.ReadByte();
    }
    public bool ReadBool()
    {
        return reader.ReadBoolean();
    }

    public byte ReadUInt8()
    {
        return ReadByte();
    }

    public short ReadShort()
    {
        return (short)reader.ReadInt16();
    }
    public ushort ReadUInt16()
    {
        return (ushort)reader.ReadUInt16();
    }
    public Int16 ReadInt16()
    {
        return ReadShort();
    }

    public int ReadInt()
    {
        return (int)reader.ReadInt32();
    }

    public uint ReadUInt32()
    {
        return (uint)reader.ReadUInt32();
    }
    public int ReadInt32()
    {
        return ReadInt();
    }

    public long ReadLong()
    {
        return (long)reader.ReadInt64();
    }

    public ulong ReadUInt64()
    {
        return (ulong)reader.ReadUInt64();
    }

    public long ReadInt64()
    {
        return ReadLong();
    }


    public ushort ReadArrayLength()
    {
        return ReadUInt16();
    }

    public float ReadFloat()
    {
        byte[] temp = BitConverter.GetBytes(reader.ReadSingle());
        ////Array.Reverse(temp);
        return BitConverter.ToSingle(temp, 0);
    }

    public double ReadDouble()
    {
        byte[] temp = BitConverter.GetBytes(reader.ReadDouble());
        //Array.Reverse(temp);
        return BitConverter.ToDouble(temp, 0);
    }

    public string ReadString()
    {
        ushort len = ReadUInt16();
        byte[] buffer = new byte[len];
        buffer = reader.ReadBytes(len);
        return Encoding.UTF8.GetString(buffer);
    }
    public List<Byte> ReadVecUInt8()
    {
        UInt16 len = ReadArrayLength();
        List<Byte> val = new List<Byte>(len);
        for (int i = 0; i < len; ++i)
            val.Add(ReadUInt8());
        return val;
    }

    public List<Byte> ReadVec2UInt8()
    {
        List<Byte> vec = new List<Byte>();
        while (true)
        {
            Byte v = ReadUInt8();
            if (v == 0)
                break;
            vec.Add(v);
        }
        return vec;
    }

    public List<UInt32> ReadVecUInt32()
    {
        UInt16 len = ReadArrayLength();
        List<UInt32> vec = new List<UInt32>(len);
        for (int i = 0; i < len; ++i)
            vec.Add(ReadUInt32());
        return vec;
    }

    public List<UInt64> ReadVecUInt64()
    {
        UInt16 len = ReadArrayLength();
        List<UInt64> vec = new List<UInt64>(len);
        for (int i = 0; i < len; ++i)
            vec.Add(ReadUInt64());
        return vec;
    }

    public List<UInt64> ReadVec2UInt64()
    {
        List<UInt64> vec = new List<UInt64>();
        while (true)
        {
            UInt64 v = ReadUInt64();
            if (v == 0)
                break;
            vec.Add(v);
        }
        return vec;
    }

    public List<string> ReadVecString()
    {
        UInt16 len = ReadArrayLength();
        List<string> vec = new List<string>(len);
        for (int i = 0; i < len; ++i)
            vec.Add(ReadString());
        return vec;
    }

    public byte[] ReadBytes()
    {
        ushort len = ReadUInt16();
        return reader.ReadBytes(len);
    }

    public byte[] ToBytes()
    {
        writer.Flush();
        return stream.ToArray();
    }

    public void Flush()
    {
        writer.Flush();
    }
}
